// File generated from our OpenAPI spec
package com.stripe.model;

import com.google.gson.annotations.SerializedName;
import com.stripe.exception.StripeException;
import com.stripe.net.ApiRequest;
import com.stripe.net.ApiRequestParams;
import com.stripe.net.ApiResource;
import com.stripe.net.BaseAddress;
import com.stripe.net.RequestOptions;
import com.stripe.net.StripeResponseGetter;
import com.stripe.param.RefundCancelParams;
import com.stripe.param.RefundCreateParams;
import com.stripe.param.RefundExpireParams;
import com.stripe.param.RefundListParams;
import com.stripe.param.RefundRetrieveParams;
import com.stripe.param.RefundUpdateParams;
import java.util.Map;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

/**
 * Refund objects allow you to refund a previously created charge that isn't refunded yet. Funds are
 * refunded to the credit or debit card that's initially charged.
 *
 * <p>Related guide: <a href="https://stripe.com/docs/refunds">Refunds</a>
 */
@Getter
@Setter
@EqualsAndHashCode(callSuper = false)
public class Refund extends ApiResource implements MetadataStore<Refund>, BalanceTransactionSource {
  /** Amount, in cents (or local equivalent). */
  @SerializedName("amount")
  Long amount;

  /** Balance transaction that describes the impact on your account balance. */
  @SerializedName("balance_transaction")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<BalanceTransaction> balanceTransaction;

  /** ID of the charge that's refunded. */
  @SerializedName("charge")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<Charge> charge;

  /** Time at which the object was created. Measured in seconds since the Unix epoch. */
  @SerializedName("created")
  Long created;

  /**
   * Three-letter <a href="https://www.iso.org/iso-4217-currency-codes.html">ISO currency code</a>,
   * in lowercase. Must be a <a href="https://stripe.com/docs/currencies">supported currency</a>.
   */
  @SerializedName("currency")
  String currency;

  /**
   * An arbitrary string attached to the object. You can use this for displaying to users (available
   * on non-card refunds only).
   */
  @SerializedName("description")
  String description;

  @SerializedName("destination_details")
  DestinationDetails destinationDetails;

  /**
   * After the refund fails, this balance transaction describes the adjustment made on your account
   * balance that reverses the initial balance transaction.
   */
  @SerializedName("failure_balance_transaction")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<BalanceTransaction> failureBalanceTransaction;

  /**
   * Provides the reason for the refund failure. Possible values are: {@code lost_or_stolen_card},
   * {@code expired_or_canceled_card}, {@code charge_for_pending_refund_disputed}, {@code
   * insufficient_funds}, {@code declined}, {@code merchant_request}, or {@code unknown}.
   */
  @SerializedName("failure_reason")
  String failureReason;

  /** Unique identifier for the object. */
  @Getter(onMethod_ = {@Override})
  @SerializedName("id")
  String id;

  /**
   * For payment methods without native refund support (for example, Konbini, PromptPay), provide an
   * email address for the customer to receive refund instructions.
   */
  @SerializedName("instructions_email")
  String instructionsEmail;

  /**
   * Set of <a href="https://stripe.com/docs/api/metadata">key-value pairs</a> that you can attach
   * to an object. This can be useful for storing additional information about the object in a
   * structured format.
   */
  @Getter(onMethod_ = {@Override})
  @SerializedName("metadata")
  Map<String, String> metadata;

  @SerializedName("next_action")
  NextAction nextAction;

  /**
   * String representing the object's type. Objects of the same type share the same value.
   *
   * <p>Equal to {@code refund}.
   */
  @SerializedName("object")
  String object;

  /** ID of the PaymentIntent that's refunded. */
  @SerializedName("payment_intent")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<PaymentIntent> paymentIntent;

  /**
   * Provides the reason for why the refund is pending. Possible values are: {@code processing},
   * {@code insufficient_funds}, or {@code charge_pending}.
   *
   * <p>One of {@code charge_pending}, {@code insufficient_funds}, or {@code processing}.
   */
  @SerializedName("pending_reason")
  String pendingReason;

  @SerializedName("presentment_details")
  PresentmentDetails presentmentDetails;

  /**
   * Reason for the refund, which is either user-provided ({@code duplicate}, {@code fraudulent}, or
   * {@code requested_by_customer}) or generated by Stripe internally ({@code
   * expired_uncaptured_charge}).
   *
   * <p>One of {@code duplicate}, {@code expired_uncaptured_charge}, {@code fraudulent}, or {@code
   * requested_by_customer}.
   */
  @SerializedName("reason")
  String reason;

  /** This is the transaction number that appears on email receipts sent for this refund. */
  @SerializedName("receipt_number")
  String receiptNumber;

  /**
   * The transfer reversal that's associated with the refund. Only present if the charge came from
   * another Stripe account.
   */
  @SerializedName("source_transfer_reversal")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<TransferReversal> sourceTransferReversal;

  /**
   * Status of the refund. This can be {@code pending}, {@code requires_action}, {@code succeeded},
   * {@code failed}, or {@code canceled}. Learn more about <a
   * href="https://stripe.com/docs/refunds#failed-refunds">failed refunds</a>.
   */
  @SerializedName("status")
  String status;

  /**
   * This refers to the transfer reversal object if the accompanying transfer reverses. This is only
   * applicable if the charge was created using the destination parameter.
   */
  @SerializedName("transfer_reversal")
  @Getter(lombok.AccessLevel.NONE)
  @Setter(lombok.AccessLevel.NONE)
  ExpandableField<TransferReversal> transferReversal;

  /** Get ID of expandable {@code balanceTransaction} object. */
  public String getBalanceTransaction() {
    return (this.balanceTransaction != null) ? this.balanceTransaction.getId() : null;
  }

  public void setBalanceTransaction(String id) {
    this.balanceTransaction = ApiResource.setExpandableFieldId(id, this.balanceTransaction);
  }

  /** Get expanded {@code balanceTransaction}. */
  public BalanceTransaction getBalanceTransactionObject() {
    return (this.balanceTransaction != null) ? this.balanceTransaction.getExpanded() : null;
  }

  public void setBalanceTransactionObject(BalanceTransaction expandableObject) {
    this.balanceTransaction =
        new ExpandableField<BalanceTransaction>(expandableObject.getId(), expandableObject);
  }

  /** Get ID of expandable {@code charge} object. */
  public String getCharge() {
    return (this.charge != null) ? this.charge.getId() : null;
  }

  public void setCharge(String id) {
    this.charge = ApiResource.setExpandableFieldId(id, this.charge);
  }

  /** Get expanded {@code charge}. */
  public Charge getChargeObject() {
    return (this.charge != null) ? this.charge.getExpanded() : null;
  }

  public void setChargeObject(Charge expandableObject) {
    this.charge = new ExpandableField<Charge>(expandableObject.getId(), expandableObject);
  }

  /** Get ID of expandable {@code failureBalanceTransaction} object. */
  public String getFailureBalanceTransaction() {
    return (this.failureBalanceTransaction != null) ? this.failureBalanceTransaction.getId() : null;
  }

  public void setFailureBalanceTransaction(String id) {
    this.failureBalanceTransaction =
        ApiResource.setExpandableFieldId(id, this.failureBalanceTransaction);
  }

  /** Get expanded {@code failureBalanceTransaction}. */
  public BalanceTransaction getFailureBalanceTransactionObject() {
    return (this.failureBalanceTransaction != null)
        ? this.failureBalanceTransaction.getExpanded()
        : null;
  }

  public void setFailureBalanceTransactionObject(BalanceTransaction expandableObject) {
    this.failureBalanceTransaction =
        new ExpandableField<BalanceTransaction>(expandableObject.getId(), expandableObject);
  }

  /** Get ID of expandable {@code paymentIntent} object. */
  public String getPaymentIntent() {
    return (this.paymentIntent != null) ? this.paymentIntent.getId() : null;
  }

  public void setPaymentIntent(String id) {
    this.paymentIntent = ApiResource.setExpandableFieldId(id, this.paymentIntent);
  }

  /** Get expanded {@code paymentIntent}. */
  public PaymentIntent getPaymentIntentObject() {
    return (this.paymentIntent != null) ? this.paymentIntent.getExpanded() : null;
  }

  public void setPaymentIntentObject(PaymentIntent expandableObject) {
    this.paymentIntent =
        new ExpandableField<PaymentIntent>(expandableObject.getId(), expandableObject);
  }

  /** Get ID of expandable {@code sourceTransferReversal} object. */
  public String getSourceTransferReversal() {
    return (this.sourceTransferReversal != null) ? this.sourceTransferReversal.getId() : null;
  }

  public void setSourceTransferReversal(String id) {
    this.sourceTransferReversal = ApiResource.setExpandableFieldId(id, this.sourceTransferReversal);
  }

  /** Get expanded {@code sourceTransferReversal}. */
  public TransferReversal getSourceTransferReversalObject() {
    return (this.sourceTransferReversal != null) ? this.sourceTransferReversal.getExpanded() : null;
  }

  public void setSourceTransferReversalObject(TransferReversal expandableObject) {
    this.sourceTransferReversal =
        new ExpandableField<TransferReversal>(expandableObject.getId(), expandableObject);
  }

  /** Get ID of expandable {@code transferReversal} object. */
  public String getTransferReversal() {
    return (this.transferReversal != null) ? this.transferReversal.getId() : null;
  }

  public void setTransferReversal(String id) {
    this.transferReversal = ApiResource.setExpandableFieldId(id, this.transferReversal);
  }

  /** Get expanded {@code transferReversal}. */
  public TransferReversal getTransferReversalObject() {
    return (this.transferReversal != null) ? this.transferReversal.getExpanded() : null;
  }

  public void setTransferReversalObject(TransferReversal expandableObject) {
    this.transferReversal =
        new ExpandableField<TransferReversal>(expandableObject.getId(), expandableObject);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel() throws StripeException {
    return cancel((Map<String, Object>) null, (RequestOptions) null);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel(RequestOptions options) throws StripeException {
    return cancel((Map<String, Object>) null, options);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel(Map<String, Object> params) throws StripeException {
    return cancel(params, (RequestOptions) null);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel(Map<String, Object> params, RequestOptions options) throws StripeException {
    String path = String.format("/v1/refunds/%s/cancel", ApiResource.urlEncodeId(this.getId()));
    ApiRequest request =
        new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.POST, path, params, options);
    return getResponseGetter().request(request, Refund.class);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel(RefundCancelParams params) throws StripeException {
    return cancel(params, (RequestOptions) null);
  }

  /**
   * Cancels a refund with a status of {@code requires_action}.
   *
   * <p>You can’t cancel refunds in other states. Only refunds for payment methods that require
   * customer action can enter the {@code requires_action} state.
   */
  public Refund cancel(RefundCancelParams params, RequestOptions options) throws StripeException {
    String path = String.format("/v1/refunds/%s/cancel", ApiResource.urlEncodeId(this.getId()));
    ApiResource.checkNullTypedParams(path, params);
    ApiRequest request =
        new ApiRequest(
            BaseAddress.API,
            ApiResource.RequestMethod.POST,
            path,
            ApiRequestParams.paramsToMap(params),
            options);
    return getResponseGetter().request(request, Refund.class);
  }

  /**
   * When you create a new refund, you must specify a Charge or a PaymentIntent object on which to
   * create it.
   *
   * <p>Creating a new refund will refund a charge that has previously been created but not yet
   * refunded. Funds will be refunded to the credit or debit card that was originally charged.
   *
   * <p>You can optionally refund only part of a charge. You can do so multiple times, until the
   * entire charge has been refunded.
   *
   * <p>Once entirely refunded, a charge can’t be refunded again. This method will raise an error
   * when called on an already-refunded charge, or when trying to refund more money than is left on
   * a charge.
   */
  public static Refund create(Map<String, Object> params) throws StripeException {
    return create(params, (RequestOptions) null);
  }

  /**
   * When you create a new refund, you must specify a Charge or a PaymentIntent object on which to
   * create it.
   *
   * <p>Creating a new refund will refund a charge that has previously been created but not yet
   * refunded. Funds will be refunded to the credit or debit card that was originally charged.
   *
   * <p>You can optionally refund only part of a charge. You can do so multiple times, until the
   * entire charge has been refunded.
   *
   * <p>Once entirely refunded, a charge can’t be refunded again. This method will raise an error
   * when called on an already-refunded charge, or when trying to refund more money than is left on
   * a charge.
   */
  public static Refund create(Map<String, Object> params, RequestOptions options)
      throws StripeException {
    String path = "/v1/refunds";
    ApiRequest request =
        new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.POST, path, params, options);
    return getGlobalResponseGetter().request(request, Refund.class);
  }

  /**
   * When you create a new refund, you must specify a Charge or a PaymentIntent object on which to
   * create it.
   *
   * <p>Creating a new refund will refund a charge that has previously been created but not yet
   * refunded. Funds will be refunded to the credit or debit card that was originally charged.
   *
   * <p>You can optionally refund only part of a charge. You can do so multiple times, until the
   * entire charge has been refunded.
   *
   * <p>Once entirely refunded, a charge can’t be refunded again. This method will raise an error
   * when called on an already-refunded charge, or when trying to refund more money than is left on
   * a charge.
   */
  public static Refund create(RefundCreateParams params) throws StripeException {
    return create(params, (RequestOptions) null);
  }

  /**
   * When you create a new refund, you must specify a Charge or a PaymentIntent object on which to
   * create it.
   *
   * <p>Creating a new refund will refund a charge that has previously been created but not yet
   * refunded. Funds will be refunded to the credit or debit card that was originally charged.
   *
   * <p>You can optionally refund only part of a charge. You can do so multiple times, until the
   * entire charge has been refunded.
   *
   * <p>Once entirely refunded, a charge can’t be refunded again. This method will raise an error
   * when called on an already-refunded charge, or when trying to refund more money than is left on
   * a charge.
   */
  public static Refund create(RefundCreateParams params, RequestOptions options)
      throws StripeException {
    String path = "/v1/refunds";
    ApiResource.checkNullTypedParams(path, params);
    ApiRequest request =
        new ApiRequest(
            BaseAddress.API,
            ApiResource.RequestMethod.POST,
            path,
            ApiRequestParams.paramsToMap(params),
            options);
    return getGlobalResponseGetter().request(request, Refund.class);
  }

  /**
   * Returns a list of all refunds you created. We return the refunds in sorted order, with the most
   * recent refunds appearing first. The 10 most recent refunds are always available by default on
   * the Charge object.
   */
  public static RefundCollection list(Map<String, Object> params) throws StripeException {
    return list(params, (RequestOptions) null);
  }

  /**
   * Returns a list of all refunds you created. We return the refunds in sorted order, with the most
   * recent refunds appearing first. The 10 most recent refunds are always available by default on
   * the Charge object.
   */
  public static RefundCollection list(Map<String, Object> params, RequestOptions options)
      throws StripeException {
    String path = "/v1/refunds";
    ApiRequest request =
        new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.GET, path, params, options);
    return getGlobalResponseGetter().request(request, RefundCollection.class);
  }

  /**
   * Returns a list of all refunds you created. We return the refunds in sorted order, with the most
   * recent refunds appearing first. The 10 most recent refunds are always available by default on
   * the Charge object.
   */
  public static RefundCollection list(RefundListParams params) throws StripeException {
    return list(params, (RequestOptions) null);
  }

  /**
   * Returns a list of all refunds you created. We return the refunds in sorted order, with the most
   * recent refunds appearing first. The 10 most recent refunds are always available by default on
   * the Charge object.
   */
  public static RefundCollection list(RefundListParams params, RequestOptions options)
      throws StripeException {
    String path = "/v1/refunds";
    ApiResource.checkNullTypedParams(path, params);
    ApiRequest request =
        new ApiRequest(
            BaseAddress.API,
            ApiResource.RequestMethod.GET,
            path,
            ApiRequestParams.paramsToMap(params),
            options);
    return getGlobalResponseGetter().request(request, RefundCollection.class);
  }

  /** Retrieves the details of an existing refund. */
  public static Refund retrieve(String refund) throws StripeException {
    return retrieve(refund, (Map<String, Object>) null, (RequestOptions) null);
  }

  /** Retrieves the details of an existing refund. */
  public static Refund retrieve(String refund, RequestOptions options) throws StripeException {
    return retrieve(refund, (Map<String, Object>) null, options);
  }

  /** Retrieves the details of an existing refund. */
  public static Refund retrieve(String refund, Map<String, Object> params, RequestOptions options)
      throws StripeException {
    String path = String.format("/v1/refunds/%s", ApiResource.urlEncodeId(refund));
    ApiRequest request =
        new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.GET, path, params, options);
    return getGlobalResponseGetter().request(request, Refund.class);
  }

  /** Retrieves the details of an existing refund. */
  public static Refund retrieve(String refund, RefundRetrieveParams params, RequestOptions options)
      throws StripeException {
    String path = String.format("/v1/refunds/%s", ApiResource.urlEncodeId(refund));
    ApiResource.checkNullTypedParams(path, params);
    ApiRequest request =
        new ApiRequest(
            BaseAddress.API,
            ApiResource.RequestMethod.GET,
            path,
            ApiRequestParams.paramsToMap(params),
            options);
    return getGlobalResponseGetter().request(request, Refund.class);
  }

  /**
   * Updates the refund that you specify by setting the values of the passed parameters. Any
   * parameters that you don’t provide remain unchanged.
   *
   * <p>This request only accepts {@code metadata} as an argument.
   */
  @Override
  public Refund update(Map<String, Object> params) throws StripeException {
    return update(params, (RequestOptions) null);
  }

  /**
   * Updates the refund that you specify by setting the values of the passed parameters. Any
   * parameters that you don’t provide remain unchanged.
   *
   * <p>This request only accepts {@code metadata} as an argument.
   */
  @Override
  public Refund update(Map<String, Object> params, RequestOptions options) throws StripeException {
    String path = String.format("/v1/refunds/%s", ApiResource.urlEncodeId(this.getId()));
    ApiRequest request =
        new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.POST, path, params, options);
    return getResponseGetter().request(request, Refund.class);
  }

  /**
   * Updates the refund that you specify by setting the values of the passed parameters. Any
   * parameters that you don’t provide remain unchanged.
   *
   * <p>This request only accepts {@code metadata} as an argument.
   */
  public Refund update(RefundUpdateParams params) throws StripeException {
    return update(params, (RequestOptions) null);
  }

  /**
   * Updates the refund that you specify by setting the values of the passed parameters. Any
   * parameters that you don’t provide remain unchanged.
   *
   * <p>This request only accepts {@code metadata} as an argument.
   */
  public Refund update(RefundUpdateParams params, RequestOptions options) throws StripeException {
    String path = String.format("/v1/refunds/%s", ApiResource.urlEncodeId(this.getId()));
    ApiResource.checkNullTypedParams(path, params);
    ApiRequest request =
        new ApiRequest(
            BaseAddress.API,
            ApiResource.RequestMethod.POST,
            path,
            ApiRequestParams.paramsToMap(params),
            options);
    return getResponseGetter().request(request, Refund.class);
  }

  /**
   * For more details about DestinationDetails, please refer to the <a
   * href="https://docs.stripe.com/api">API Reference.</a>
   */
  @Getter
  @Setter
  @EqualsAndHashCode(callSuper = false)
  public static class DestinationDetails extends StripeObject {
    @SerializedName("affirm")
    Affirm affirm;

    @SerializedName("afterpay_clearpay")
    AfterpayClearpay afterpayClearpay;

    @SerializedName("alipay")
    Alipay alipay;

    @SerializedName("alma")
    Alma alma;

    @SerializedName("amazon_pay")
    AmazonPay amazonPay;

    @SerializedName("au_bank_transfer")
    AuBankTransfer auBankTransfer;

    @SerializedName("blik")
    Blik blik;

    @SerializedName("br_bank_transfer")
    BrBankTransfer brBankTransfer;

    @SerializedName("card")
    Card card;

    @SerializedName("cashapp")
    Cashapp cashapp;

    @SerializedName("crypto")
    Crypto crypto;

    @SerializedName("customer_cash_balance")
    CustomerCashBalance customerCashBalance;

    @SerializedName("eps")
    Eps eps;

    @SerializedName("eu_bank_transfer")
    EuBankTransfer euBankTransfer;

    @SerializedName("gb_bank_transfer")
    GbBankTransfer gbBankTransfer;

    @SerializedName("giropay")
    Giropay giropay;

    @SerializedName("grabpay")
    Grabpay grabpay;

    @SerializedName("jp_bank_transfer")
    JpBankTransfer jpBankTransfer;

    @SerializedName("klarna")
    Klarna klarna;

    @SerializedName("mb_way")
    MbWay mbWay;

    @SerializedName("multibanco")
    Multibanco multibanco;

    @SerializedName("mx_bank_transfer")
    MxBankTransfer mxBankTransfer;

    @SerializedName("nz_bank_transfer")
    NzBankTransfer nzBankTransfer;

    @SerializedName("p24")
    P24 p24;

    @SerializedName("paynow")
    Paynow paynow;

    @SerializedName("paypal")
    Paypal paypal;

    @SerializedName("pix")
    Pix pix;

    @SerializedName("revolut")
    Revolut revolut;

    @SerializedName("sofort")
    Sofort sofort;

    @SerializedName("swish")
    Swish swish;

    @SerializedName("th_bank_transfer")
    ThBankTransfer thBankTransfer;

    @SerializedName("twint")
    Twint twint;

    /**
     * The type of transaction-specific details of the payment method used in the refund (e.g.,
     * {@code card}). An additional hash is included on {@code destination_details} with a name
     * matching this value. It contains information specific to the refund transaction.
     */
    @SerializedName("type")
    String type;

    @SerializedName("us_bank_transfer")
    UsBankTransfer usBankTransfer;

    @SerializedName("wechat_pay")
    WechatPay wechatPay;

    @SerializedName("zip")
    Zip zip;

    /**
     * For more details about Affirm, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Affirm extends StripeObject {}

    /**
     * For more details about AfterpayClearpay, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class AfterpayClearpay extends StripeObject {}

    /**
     * For more details about Alipay, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Alipay extends StripeObject {}

    /**
     * For more details about Alma, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Alma extends StripeObject {}

    /**
     * For more details about AmazonPay, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class AmazonPay extends StripeObject {}

    /**
     * For more details about AuBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class AuBankTransfer extends StripeObject {}

    /**
     * For more details about Blik, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Blik extends StripeObject {
      /**
       * For refunds declined by the network, a decline code provided by the network which indicates
       * the reason the refund failed.
       */
      @SerializedName("network_decline_code")
      String networkDeclineCode;

      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about BrBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class BrBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Card, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Card extends StripeObject {
      /** Value of the reference number assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference number on the refund. This can be {@code pending}, {@code
       * available} or {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;

      /** Type of the reference number assigned to the refund. */
      @SerializedName("reference_type")
      String referenceType;

      /**
       * The type of refund. This can be {@code refund}, {@code reversal}, or {@code pending}.
       *
       * <p>One of {@code pending}, {@code refund}, or {@code reversal}.
       */
      @SerializedName("type")
      String type;
    }

    /**
     * For more details about Cashapp, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Cashapp extends StripeObject {}

    /**
     * For more details about Crypto, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Crypto extends StripeObject {
      /** The transaction hash of the refund. */
      @SerializedName("reference")
      String reference;
    }

    /**
     * For more details about CustomerCashBalance, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class CustomerCashBalance extends StripeObject {}

    /**
     * For more details about Eps, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Eps extends StripeObject {}

    /**
     * For more details about EuBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class EuBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about GbBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class GbBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Giropay, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Giropay extends StripeObject {}

    /**
     * For more details about Grabpay, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Grabpay extends StripeObject {}

    /**
     * For more details about JpBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class JpBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Klarna, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Klarna extends StripeObject {}

    /**
     * For more details about MbWay, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class MbWay extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Multibanco, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Multibanco extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about MxBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class MxBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about NzBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class NzBankTransfer extends StripeObject {}

    /**
     * For more details about P24, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class P24 extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Paynow, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Paynow extends StripeObject {}

    /**
     * For more details about Paypal, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Paypal extends StripeObject {
      /**
       * For refunds declined by the network, a decline code provided by the network which indicates
       * the reason the refund failed.
       */
      @SerializedName("network_decline_code")
      String networkDeclineCode;
    }

    /**
     * For more details about Pix, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Pix extends StripeObject {}

    /**
     * For more details about Revolut, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Revolut extends StripeObject {}

    /**
     * For more details about Sofort, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Sofort extends StripeObject {}

    /**
     * For more details about Swish, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Swish extends StripeObject {
      /**
       * For refunds declined by the network, a decline code provided by the network which indicates
       * the reason the refund failed.
       */
      @SerializedName("network_decline_code")
      String networkDeclineCode;

      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about ThBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class ThBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about Twint, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Twint extends StripeObject {}

    /**
     * For more details about UsBankTransfer, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class UsBankTransfer extends StripeObject {
      /** The reference assigned to the refund. */
      @SerializedName("reference")
      String reference;

      /**
       * Status of the reference on the refund. This can be {@code pending}, {@code available} or
       * {@code unavailable}.
       */
      @SerializedName("reference_status")
      String referenceStatus;
    }

    /**
     * For more details about WechatPay, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class WechatPay extends StripeObject {}

    /**
     * For more details about Zip, please refer to the <a href="https://docs.stripe.com/api">API
     * Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class Zip extends StripeObject {}
  }

  /**
   * For more details about NextAction, please refer to the <a
   * href="https://docs.stripe.com/api">API Reference.</a>
   */
  @Getter
  @Setter
  @EqualsAndHashCode(callSuper = false)
  public static class NextAction extends StripeObject {
    @SerializedName("display_details")
    DisplayDetails displayDetails;

    /** Type of the next action to perform. */
    @SerializedName("type")
    String type;

    /**
     * For more details about DisplayDetails, please refer to the <a
     * href="https://docs.stripe.com/api">API Reference.</a>
     */
    @Getter
    @Setter
    @EqualsAndHashCode(callSuper = false)
    public static class DisplayDetails extends StripeObject {
      @SerializedName("email_sent")
      EmailSent emailSent;

      /** The expiry timestamp. */
      @SerializedName("expires_at")
      Long expiresAt;

      /**
       * For more details about EmailSent, please refer to the <a
       * href="https://docs.stripe.com/api">API Reference.</a>
       */
      @Getter
      @Setter
      @EqualsAndHashCode(callSuper = false)
      public static class EmailSent extends StripeObject {
        /** The timestamp when the email was sent. */
        @SerializedName("email_sent_at")
        Long emailSentAt;

        /** The recipient's email address. */
        @SerializedName("email_sent_to")
        String emailSentTo;
      }
    }
  }

  /**
   * For more details about PresentmentDetails, please refer to the <a
   * href="https://docs.stripe.com/api">API Reference.</a>
   */
  @Getter
  @Setter
  @EqualsAndHashCode(callSuper = false)
  public static class PresentmentDetails extends StripeObject {
    /**
     * Amount intended to be collected by this payment, denominated in {@code presentment_currency}.
     */
    @SerializedName("presentment_amount")
    Long presentmentAmount;

    /** Currency presented to the customer during payment. */
    @SerializedName("presentment_currency")
    String presentmentCurrency;
  }

  public TestHelpers getTestHelpers() {
    return new TestHelpers(this);
  }

  public static class TestHelpers {
    private final Refund resource;

    private TestHelpers(Refund resource) {
      this.resource = resource;
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire() throws StripeException {
      return expire((Map<String, Object>) null, (RequestOptions) null);
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire(RequestOptions options) throws StripeException {
      return expire((Map<String, Object>) null, options);
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire(Map<String, Object> params) throws StripeException {
      return expire(params, (RequestOptions) null);
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire(Map<String, Object> params, RequestOptions options)
        throws StripeException {
      String path =
          String.format(
              "/v1/test_helpers/refunds/%s/expire", ApiResource.urlEncodeId(this.resource.getId()));
      ApiRequest request =
          new ApiRequest(BaseAddress.API, ApiResource.RequestMethod.POST, path, params, options);
      return resource.getResponseGetter().request(request, Refund.class);
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire(RefundExpireParams params) throws StripeException {
      return expire(params, (RequestOptions) null);
    }

    /** Expire a refund with a status of {@code requires_action}. */
    public Refund expire(RefundExpireParams params, RequestOptions options) throws StripeException {
      String path =
          String.format(
              "/v1/test_helpers/refunds/%s/expire", ApiResource.urlEncodeId(this.resource.getId()));
      ApiResource.checkNullTypedParams(path, params);
      ApiRequest request =
          new ApiRequest(
              BaseAddress.API,
              ApiResource.RequestMethod.POST,
              path,
              ApiRequestParams.paramsToMap(params),
              options);
      return resource.getResponseGetter().request(request, Refund.class);
    }
  }

  @Override
  public void setResponseGetter(StripeResponseGetter responseGetter) {
    super.setResponseGetter(responseGetter);
    trySetResponseGetter(balanceTransaction, responseGetter);
    trySetResponseGetter(charge, responseGetter);
    trySetResponseGetter(destinationDetails, responseGetter);
    trySetResponseGetter(failureBalanceTransaction, responseGetter);
    trySetResponseGetter(nextAction, responseGetter);
    trySetResponseGetter(paymentIntent, responseGetter);
    trySetResponseGetter(presentmentDetails, responseGetter);
    trySetResponseGetter(sourceTransferReversal, responseGetter);
    trySetResponseGetter(transferReversal, responseGetter);
  }
}
